#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <algorithm>
#include <array>
using namespace std;

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

//template<typename T>
//void PerfectForward(T&& t)
//{
//	Fun(t);
//}

//完美转发保留右值属性

// 引用
// 传左值->左值引用
// 传右值->右值引用
template<typename T>
void PerfectForward(T&& t) //万能引用/引用折叠
{
	// 模版实例化是左值引用，保持属性直接传参给Fun
	// 模版实例化是右值引用，右值引用属性会退化成左值，转换成右值属性再传参给Fun
	//cout << typeid(t).name() << endl;
	Fun(forward<T>(t)); //完美转发
}

//void PerfectForward(int& t){Fun(t);}
//
//void PerfectForward(int&& t){Fun(move(t));}
//
//void PerfectForward(const int& t) {Fun(t);}
//
//void PerfectForward(const int&& t){Fun(move(t));}


int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值

	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);			  // const 左值
	PerfectForward(std::move(b)); // const 右值

	return 0;
}


//#include "string.h"
//自动生成移动构造
//对于Date这样的类，没啥意义和拷贝构造功能是一样的
//对于下面Person这样的类很有意义，因为Person是右值时，其内部的string也是右值，string就可以走移动构造，提高效率了

//class Person
//{
//public:
//	Person(const char* name = "111111111111", int age = 0)
//		:_name(name)
//		, _age(age)
//	{}
//
//	//Person(Person&& p) = default;
//	//Person& operator=(Person && p) = default;
//	//Person(const Person& p) = default;
//	//Person& operator=(const Person& p) = default;
//
//	// 自动生成拷贝构造和移动构造
//	/*~Person()
//	{}*/
//
//private:
//	bit::string _name;
//	int _age;
//};

//
//int main()
//{
//	Person s1;
//	Person s2 = s1;
//	Person s3 = std::move(s1);
//
//	Person s4;
//	s4 = std::move(s2);
//
//	return 0;
//}


//class Person
//{
//public:
//	Person(const char* name = "111111111111", int age = 0)
//		:_name(name)
//		, _age(age)
//	{}
//
//	// 只声明不实现，声明为私有
//	// C++98
////private:
////	Person(const Person& p);
////	Person& operator=(const Person & p);
//
//	//Person(const Person& p) = delete;
//	//Person& operator=(const Person& p) = delete;
//private:
//	bit::string _name;
//	int _age;
//};
//
//Person::Person(const Person& p) //只声明不实现
//{}

//int main()
//{
//	Person s1;
//	Person s2 = s1;
//	Person s3 = std::move(s1);
//
//	Person s4;
//	s4 = std::move(s2);
//
//	return 0;
//}



//———————— 可变参数模板————————
///////////////////////////////////////////////

//template <class ...Args>
//void ShowList(Args... args)
//{}

//template <class ...T>
//void ShowList1(T... x)
//{}
//
//template <class ...Args>
//void ShowList2(Args&&... args)
//{}

//
 //可变模版参数
 //参数类型可变
 //参数个数可变
 //打印参数包内容

////定义时放前面，解包时放后面
//template<typename T, typename ...Args>
//void Show()
//{
//	array(T, Args...)->array<T, sizeof...(Args) + 1>;
//	char arr[] = { (cout << Args << ' ',0)... };
//}


//template <class ...Args>
//void ShowList(Args... args)
//{
//	// 可变参数模版编译时解析
//	// 下面是运行获取和解析，所以不支持这样用
//	cout << sizeof...(args) << endl;
//	/*for (size_t i = 0; i < sizeof...(args); i++)
//	{
//		cout << args[i] << " ";
//	}
//	cout << endl;*/
//}

//void Print() //用一个无参的来进行匹配
//{
//	cout << endl;
//}
//
//template <class T, class ...Args>
//void Print(T&& x, Args&&... args) //三个参数包，先分析参数包类型
//{
//	cout << x << " "; //打印第一个参数
//	Print(args...); //递归调用
//}
//
//// 编译时递归推导解析参数
//template <class ...Args>
//void ShowList(Args&&... args)
//{
//	Print(args...);
//}
//
//int main()
//{
//	ShowList();
//	ShowList(1);
//	ShowList(1, "xxxxx");
//	ShowList(1, "xxxxx", 2.2);
//
//	return 0;
//}

// —————————— ——————————
//void Print()
//{
//	cout << endl;
//}
//
//template <class T, class ...Args>
//void Print(T&& x, Args&&... args)
//{
//	cout << x << " ";
//	Print(args...);
//}
// 
// //编译器推导的
//void Print(double x)
//{
//	cout << x << " ";
//	Print();
//}
//
//void Print(const char* x, double z)
//{
//	cout << x << " ";
//	Print(z);
//}
//
//void Print(int x, const char* y, double z)
//{
//	cout << x << " ";
//	Print(y, z);
//}
//
//// 编译时递归推导解析参数
//template <class ...Args>
//void ShowList(Args&&... args)
//{
//	Print(args...);
//}
//
//// 编译器实例化生成
////之所以写成这样，是帮助我们节省了很多没必要的模板
//void ShowList(int x, const char* y, double z)
//{
//	Print(x, y, z);
//}
//
//int main()
//{
//	ShowList(1, "xxxxx", 2.2);
//	ShowList(1, "xxxxx", 2.2,10.2,141,4.0);
//
//	return 0;
//}



//—————— 解析的第二种方式 ————————
//template <class T>
//int PrintArg(T t)
//{
//	cout << t << " ";
//	return 0;
//}
//
//template <class ...Args>
//void ShowList(Args... args)
//{
//	int arr[] = { PrintArg(args)... };
//	cout << endl;
//}
// 
//// 编译推演生成下面的函数
//void ShowList(int x, char y, std::string z) //参数包换算之后就是这样的
//{
//	int arr[] = { PrintArg(x),PrintArg(y),PrintArg(z) }; //编译器通过解包生成的就是这个
//	cout << endl;
//}
//
//int main()
//{
//	//ShowList(1);
//	//ShowList(1, 'A');
//	ShowList(1, 'A', std::string("sort"));
//
//	return 0;
//}


//// ———————— ————————
////之前去掉逗号表达式通过返回值去掉的
//template <class ...Args>
//void ShowList(Args... args)
//{
//	//int arr[] = { cout << (args) << " "... };  //这样编译通过不了
//	//ostream arr[] = { cout << (args) << " "... }; //ostream不支持拷贝，也通过不了
//	int arr[] = { (cout<<(args)<<" ", 0)...}; //加个逗号表达式，0作那个初始化
//
//	cout << endl;
//}
//
////void ShowList(int x, char y, std::string z) //相当于编译器生成了这个
////{
////	int arr[] = { (cout<<(x)<<" ", 0), (cout << (y) << " ", 0), (cout << (z) << " ", 0) };
////
////	cout << endl;
////}
//
//int main()
//{
//	ShowList(1, 'A', std::string("sort"));
//
//	return 0;
//}




// —————————— ————————
//#include "List.h"
//#include "string.h"
//// emplace_back总体而言是更高效，推荐使用
//int main()
//{
//	bit::list<bit::string> lt;
//	// 左值
//	bit::string s1("111111111111");
//	lt.emplace_back(s1);
//	//lt.emplace_back(s1, s1, s1); //不支持插入多个值
//
//	// 右值
//	lt.emplace_back(move(s1));
//
//
//	// 直接把构造string参数包往下传，直接用string参数包构造string
//	lt.emplace_back("111111111111");
//	lt.emplace_back(10, 'x');
//	cout << endl << endl;
//
//	bit::list<pair<bit::string, int>> lt1;
//	//// 构造pair + 拷贝/移动构造pair到list的节点中data上
//	pair<bit::string, int> kv("苹果", 1);
//	lt1.emplace_back(kv);
//	lt1.emplace_back(move(kv));
//	cout << endl << endl;
//
//	////////////////////////////////////////////////////////////////////
//	// 直接把构造pair参数包往下传，直接用pair参数包构造pair
//	lt1.emplace_back("苹果", 1);
//
//	return 0;
//}